﻿using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

using Darwin;

// State Machine functionnalities
using State_Machine;

// Controllers functionnalities
using Input;

using Components.SplashScreen;
using Components.MenuSystem;
using Darwin.Source.Components.World;

using SunXNA.RainbowXNA;
using SunXNA;

using Sound;

namespace MainEngine
{
    /// <summary>
    /// Enumerator for the Main menu
    /// </summary>
    enum MenuSelection
    {
        Start_Game = 0,
        Exit
    };

    /// <summary>
    /// The main engine of the game
    /// Will handle the different parts of the game
    /// Singleton pattern
    /// </summary>
    class MainEngine : DrawableGameComponent
    {
        static MainEngine inst_MainEngine = null;

        // Keep the game
        CGameEngine game;

        // The machine handles the links between menus
        private Machine gameMachine = null;

        // Menu selector (for the main menu)
        private MenuSelection menu_selector = MenuSelection.Start_Game;

        // To avoid the repeat button in menu
        private GamePadState gps;

        private Darwin.Source.Components.World.World m_World;
        private SplashScreen m_SplashScreen;
        private Menu m_MainMenu;
        private Menu m_PauseMenu;
        private SplashScreen m_Death;
        private SplashScreen m_WinRar;

        //private MainEngine() { }

        /// <summary>
        /// Constructor; loads the machine
        /// </summary>
        /// <param name="game"></param>
        private MainEngine(CGameEngine game)
            : base(game)
        {
            this.game = game;
            gameMachine = MachineLoader.Loader("Content/GameData/MachineData/GameMachine.xml");
            gameMachine.setInitialState("Start_Screen");

            m_World = new World();
            m_World.Initialise();
            m_SplashScreen = new SplashScreen();
            m_MainMenu = new Menu();
            m_PauseMenu = new Menu();
            m_Death = new SplashScreen();
            m_WinRar = new SplashScreen();
        }

        protected override void LoadContent()
        {
            m_SplashScreen.loadContent(game.Content, "Content/GameData/MenuData/SplashScreen.xml");
            m_MainMenu.loadContent(game.Content, "Content/GameData/MenuData/MainMenu.xml");
            m_PauseMenu.loadContent(game.Content, "Content/GameData/MenuData/PauseMenu.xml");
            m_World.loadContent(game.Content, "Content/GameData/WorldData/World.xml");
            m_Death.loadContent(game.Content, "Content/GameData/MenuData/Death.xml");
            m_WinRar.loadContent(game.Content, "Content/GameData/MenuData/WinRar.xml");

            base.LoadContent();
        }

        /// <summary>
        /// Getter for the MainEngine (Singleton pattern)
        /// Needs to be called before all use of the MainEngine
        /// </summary>
        /// <param name="game"></param>
        /// <returns></returns>
        public static MainEngine getMainEngine(CGameEngine game)
        {
            if (inst_MainEngine == null)
                inst_MainEngine = new MainEngine(game);
            return inst_MainEngine;
        }

        /// <summary>
        /// Getter for the MainEngine (Singleton pattern)
        /// </summary>
        /// <returns></returns>
        public static MainEngine getMainEngine()
        {
            return inst_MainEngine;
        }

        /// <summary>
        /// Updates the game and handles the transition
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
           GamePad1.getGamePadStateP1();
            
                // Dependant of the state name
                switch (gameMachine.getCurrentStateName())
                {
                    case "Start_Screen":
                        {
                            m_SplashScreen.update(gameTime);
                            if (GamePad1.isButtonStartPressedP1())
                            {
                                gameMachine.doTransition("Press_Start");
                                SoundManager.getSoundManager().playSound(0);
                            }
                        }
                        break;
                    case "Menu_Screen":
                        {
                            m_MainMenu.update(gameTime);

                            if (GamePad1.isDPadUpPressedP1() && gps.DPad.Up != ButtonState.Pressed)
                            {
                                SoundManager.getSoundManager().playSound(0);
                                if (menu_selector == MenuSelection.Start_Game)
                                {
                                    m_MainMenu.toggleButtonDraw();
                                    menu_selector = MenuSelection.Exit;
                                }
                                else
                                {
                                    m_MainMenu.toggleButtonDraw();
                                    menu_selector--;
                                }
                            }
                            if (GamePad1.isDPadDownPressedP1() && gps.DPad.Down != ButtonState.Pressed)
                            {
                                SoundManager.getSoundManager().playSound(0);
                                if (menu_selector == MenuSelection.Exit)
                                {
                                    m_MainMenu.toggleButtonDraw();
                                    menu_selector = MenuSelection.Start_Game;
                                }
                                else
                                {
                                    m_MainMenu.toggleButtonDraw();
                                    menu_selector++;
                                }
                            }
                            if (GamePad1.isButtonAPressedP1())
                            {
                                SoundManager.getSoundManager().playSound(0);
                                switch (menu_selector)
                                {
                                    case MenuSelection.Start_Game:
                                        gameMachine.doTransition("Start_Game");
                                        break;
                                    case MenuSelection.Exit:
                                        gameMachine.doTransition("Go_Exit");
                                        break;
                                }
                            }
                        }
                        break;
                    case "Game":
                        {
                            m_World.update(gameTime);

                            if (GamePad1.isButtonStartPressedP1() && gps.Buttons.Start != ButtonState.Pressed)
                            {
                                gameMachine.doTransition("GetPause");
                            }
                            else if (m_World.m_GameOver)
                            {
                                gameMachine.doTransition("Death");
                            }
                            else if (m_World.m_WinRar)
                            {
                                gameMachine.doTransition("WinRar");
                            }
                        }
                        break;
                    case "GameInPause":
                        {
                            m_PauseMenu.update(gameTime);

                            if (GamePad1.isDPadUpPressedP1() && gps.DPad.Up != ButtonState.Pressed)
                            {
                                SoundManager.getSoundManager().playSound(0);
                                if (menu_selector == MenuSelection.Start_Game)
                                {
                                    m_PauseMenu.toggleButtonDraw();
                                    menu_selector = MenuSelection.Exit;
                                }
                                else
                                {
                                    m_PauseMenu.toggleButtonDraw();
                                    menu_selector--;
                                }
                            }
                            if (GamePad1.isDPadDownPressedP1() && gps.DPad.Down != ButtonState.Pressed)
                            {
                                SoundManager.getSoundManager().playSound(0);
                                if (menu_selector == MenuSelection.Exit)
                                {
                                    m_PauseMenu.toggleButtonDraw();
                                    menu_selector = MenuSelection.Start_Game;
                                }
                                else
                                {
                                    m_PauseMenu.toggleButtonDraw();
                                    menu_selector++;
                                }
                            }
                            if (GamePad1.isButtonAPressedP1())
                            {
                                SoundManager.getSoundManager().playSound(0);
                                switch (menu_selector)
                                {
                                    case MenuSelection.Start_Game:
                                        gameMachine.doTransition("UnGetPause");
                                        break;
                                    case MenuSelection.Exit:
                                        gameMachine.doTransition("Go_Exit");
                                        break;
                                }
                            }
                        }
                        break;
                    case "Death":
                        {
                            if (GamePad1.isButtonStartPressedP1())
                            {
                                gameMachine.doTransition("Go_Exit");
                            }
                        }
                        break;
                    case "WinRar":
                        {
                            if (GamePad1.isButtonStartPressedP1())
                            {
                                gameMachine.doTransition("Go_Exit");
                            }
                        }
                        break;
                    case "Exit":
                        break;
                }
            gps = GamePad1.getGamePadStateP1();
        }

        /// <summary>
        /// Draws the game
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Draw(GameTime gameTime)
        {
            // Dependant of the state name
            switch (gameMachine.getCurrentStateName())
            {
                case "Start_Screen":
                    {
                        Singleton<CRainbowXNA>.Instance.BeginAll();
                        {
                            Singleton<CRainbowXNA>.Instance.Begin2D();
                            {
                                
                                m_SplashScreen.draw2D();
                            }
                            Singleton<CRainbowXNA>.Instance.End2D();
                        }
                        Singleton<CRainbowXNA>.Instance.EndAll();
                    }
                    break;
                case "Menu_Screen":
                    {
                        Singleton<CRainbowXNA>.Instance.BeginAll();
                        {
                            Singleton<CRainbowXNA>.Instance.Begin2D();
                            {
                                m_MainMenu.draw2D();
                            }
                            Singleton<CRainbowXNA>.Instance.End2D();
                        }
                        Singleton<CRainbowXNA>.Instance.EndAll();
                    }
                    // Draw menu screen
                    break;
                case "Game":
                    {
                        Singleton<CRainbowXNA>.Instance.BeginAll();
                        {
                            Singleton<CRainbowXNA>.Instance.Begin3D();
                            {
                                m_World.draw3D();
                            }
                            Singleton<CRainbowXNA>.Instance.End3D((float)gameTime.TotalGameTime.TotalSeconds, (float)gameTime.ElapsedGameTime.TotalSeconds);

                            Singleton<CRainbowXNA>.Instance.Begin2D();
                            {
                                m_World.draw2D();
                            }
                            Singleton<CRainbowXNA>.Instance.End2D();
                        }
                        Singleton<CRainbowXNA>.Instance.EndAll();
                    }
                    // Draw world
                    break;
                case "GameInPause":
                    {
                        Singleton<CRainbowXNA>.Instance.BeginAll();
                        {
                            Singleton<CRainbowXNA>.Instance.Begin3D();
                            {
                                m_World.draw3D();
                            }
                            Singleton<CRainbowXNA>.Instance.End3D((float)gameTime.TotalGameTime.TotalSeconds, (float)gameTime.ElapsedGameTime.TotalSeconds);

                            Singleton<CRainbowXNA>.Instance.Begin2D();
                            {
                                m_PauseMenu.draw2D();
                            }
                            Singleton<CRainbowXNA>.Instance.End2D();
                        }
                        Singleton<CRainbowXNA>.Instance.EndAll();
                    }
                    // Set pause
                    break;
                case "Death":
                    {
                        Singleton<CRainbowXNA>.Instance.BeginAll();
                        {
                            Singleton<CRainbowXNA>.Instance.Begin3D();
                            {
                                m_World.draw3D();
                            }
                            Singleton<CRainbowXNA>.Instance.End3D((float)gameTime.TotalGameTime.TotalSeconds, (float)gameTime.ElapsedGameTime.TotalSeconds);

                            Singleton<CRainbowXNA>.Instance.Begin2D();
                            {
                                m_Death.draw2D();
                            }
                            Singleton<CRainbowXNA>.Instance.End2D();
                        }
                        Singleton<CRainbowXNA>.Instance.EndAll();
                    }
                    break;
                case "WinRar":
                    {
                        Singleton<CRainbowXNA>.Instance.BeginAll();
                        {
                            Singleton<CRainbowXNA>.Instance.Begin3D();
                            {
                                m_World.draw3D();
                            }
                            Singleton<CRainbowXNA>.Instance.End3D((float)gameTime.TotalGameTime.TotalSeconds, (float)gameTime.ElapsedGameTime.TotalSeconds);

                            Singleton<CRainbowXNA>.Instance.Begin2D();
                            {
                                m_WinRar.draw2D();
                            }
                            Singleton<CRainbowXNA>.Instance.End2D();
                        }
                        Singleton<CRainbowXNA>.Instance.EndAll();
                    }
                    break;
                case "Exit":
                    game.Exit();
                    // Bye
                    break;
            }
        }
    }
}
